#include "bsp_usb.h"
#include "bsp.h"

#if (CONFIG_HAL_USB_HOST_MODULE_ENABLED)

#include "usbh_core.h"


/* define */
#define USE_USB_FS
// #define USE_USB_HS   // not support

/* extern func */
HCD_HandleTypeDef *bsp_usb_host_get_hcd(void);

/* callback func */


/* USBD_LL callback function */

USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost)
{
#ifdef USE_USB_FS
    HCD_HandleTypeDef *hhcd;

    hhcd = bsp_usb_host_get_hcd();

    /* 设置LL驱动相关参数 */
    hhcd->Instance = USB2_OTG_FS;             // 使用USB2 OTG
    hhcd->Init.Host_channels = 11;            // 主机通道数为11个
    hhcd->Init.dma_enable = 0;                // 不使用DMA
    hhcd->Init.low_power_enable = 0;          // 不使能低功耗模式
    hhcd->Init.phy_itface = HCD_PHY_EMBEDDED; // 使用内部PHY
    hhcd->Init.Sof_enable = 0;                // 禁止SOF中断
    hhcd->Init.speed = HCD_SPEED_FULL;        // USB全速(12Mbps)
    hhcd->Init.vbus_sensing_enable = 0;       // 不使能VBUS检测
    hhcd->Init.lpm_enable = 0;                // 使能连接电源管理

    hhcd->pData = phost; // hhcd的pData指向phost
    phost->pData = hhcd; // phost的pData指向hhcd

    HAL_HCD_Init(hhcd); // 初始化LL驱动
#endif

#ifdef USE_USB_HS
    // 未实现
#endif
    USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(hhcd));
    return USBH_OK;
}

/**
 * @brief USBD底层去初始化
 *
 * @param phost
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_DeInit(USBH_HandleTypeDef *phost)
{
    HAL_HCD_DeInit(phost->pData);
    return USBH_OK;
}

/**
 * @brief USBH底层驱动开始工作
 *
 * @param phost
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_Start(USBH_HandleTypeDef *phost)
{
    HAL_HCD_Start(phost->pData);
    return USBH_OK;
}

/**
 * @brief USBH底层驱动停止工作
 *
 * @param phost
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_Stop(USBH_HandleTypeDef *phost)
{
    HAL_HCD_Stop(phost->pData);
    return USBH_OK;
}

/**
 * @brief USBH获取USB设备的速度
 *
 * @param phost
 * @return USBH_SpeedTypeDef USBH设备速度
 */
USBH_SpeedTypeDef USBH_LL_GetSpeed(USBH_HandleTypeDef *phost)
{
    USBH_SpeedTypeDef speed = USBH_SPEED_FULL;
    switch (HAL_HCD_GetCurrentSpeed(phost->pData))
    {
    case 0:
        speed = USBH_SPEED_HIGH;
        printf("USB Host [HS]\r\n");
        break;
    case 1:
        speed = USBH_SPEED_FULL;
        printf("USB Host [FS]\r\n");
        break;
    case 2:
        speed = USBH_SPEED_LOW;
        printf("USB Host [LS]\r\n");
        break;
    default:
        speed = USBH_SPEED_FULL;
        printf("USB Host [FS]\r\n");
        break;
    }
    return speed;
}

/**
 * @brief USBH复位USB HOST端口
 *
 * @param phost
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_ResetPort(USBH_HandleTypeDef *phost)
{
    HAL_HCD_ResetPort(phost->pData);
    printf("USB Reset Port\r\n");
    return USBH_OK;
}

/**
 * @brief USBH获取最近一次传输的包大小
 *
 * @param phost
 * @param pipe 管道编号
 * @return uint32_t 包大小
 */
uint32_t USBH_LL_GetLastXferSize(USBH_HandleTypeDef *phost, uint8_t pipe)
{
    return HAL_HCD_HC_GetXferCount(phost->pData, pipe);
}

/**
 * @brief USBH打开一个管道(通道)
 *
 * @param phost
 * @param pipe 管道编号
 * @param epnum 端点号
 * @param dev_address 设备地址
 * @param speed 设备速度
 * @param ep_type 端点类型
 * @param mps 端点最大包大小
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_OpenPipe(USBH_HandleTypeDef *phost,
                                    uint8_t pipe,
                                    uint8_t epnum,
                                    uint8_t dev_address,
                                    uint8_t speed,
                                    uint8_t ep_type, uint16_t mps)
{
    HAL_HCD_HC_Init(phost->pData, pipe, epnum, dev_address, speed, ep_type, mps);
    return USBH_OK;
}

/**
 * @brief USBH关闭一个管道(通道)
 *
 * @param phost
 * @param pipe 管道编号
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_ClosePipe(USBH_HandleTypeDef *phost, uint8_t pipe)
{
    HAL_HCD_HC_Halt(phost->pData, pipe);
    return USBH_OK;
}

/**
 * @brief USBH提交一个新的URB
 *
 * @param phost
 * @param pipe 管道编号
 * @param direction 方向设置
 * @param ep_type 端点类型
 * @param token 端点标志
 * @param pbuff URB数据区首地址
 * @param length URB数据长度
 * @param do_ping 激活do ping protocol,USB HS才用到
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_SubmitURB(USBH_HandleTypeDef *phost,
                                     uint8_t pipe,
                                     uint8_t direction,
                                     uint8_t ep_type,
                                     uint8_t token,
                                     uint8_t *pbuff,
                                     uint16_t length, uint8_t do_ping)
{
    HAL_HCD_HC_SubmitRequest(phost->pData, pipe, direction, ep_type, token, pbuff, length, do_ping);
    return USBH_OK;
}

/**
 * @brief USBH获取URB状态
 *
 * @param phost
 * @param pipe 管道编号
 * @return USBH_URBStateTypeDef
 */
USBH_URBStateTypeDef USBH_LL_GetURBState(USBH_HandleTypeDef *phost, uint8_t pipe)
{
    return (USBH_URBStateTypeDef)HAL_HCD_HC_GetURBState(phost->pData, pipe);
}

/**
 * @brief USBH控制VBUS状态
 *
 * @param phost
 * @param state vbus状态.0,激活;1,不激活
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_DriverVBUS(USBH_HandleTypeDef *phost, uint8_t state)
{
#ifdef USE_USB_FS
    if (state == TRUE)
    {
        bsp_usb_power_on();
    }
    else
    {
        bsp_usb_power_off();
    }
#endif
    HAL_Delay(500);
    return USBH_OK;
}

/**
 * @brief USBH设置管道的翻转
 *
 * @param phost
 * @param pipe 管道编号
 * @param toggle 翻转状态.
 * @return USBH_StatusTypeDef
 */
USBH_StatusTypeDef USBH_LL_SetToggle(USBH_HandleTypeDef *phost, uint8_t pipe, uint8_t toggle)
{
    HCD_HandleTypeDef *hhcd;

    hhcd = bsp_usb_host_get_hcd();
    if (hhcd->hc[pipe].ep_is_in)
    {
        hhcd->hc[pipe].toggle_in = toggle;
    }
    else
    {
        hhcd->hc[pipe].toggle_out = toggle;
    }
    return USBH_OK;
}

/**
 * @brief USBH获取管道翻转状态
 *
 * @param phost
 * @param pipe  管道编号
 * @return uint8_t 翻转状态
 */
uint8_t USBH_LL_GetToggle(USBH_HandleTypeDef *phost, uint8_t pipe)
{
    uint8_t toggle = 0;
    HCD_HandleTypeDef *hhcd;

    hhcd = bsp_usb_host_get_hcd();
    if (hhcd->hc[pipe].ep_is_in)
    {
        toggle = hhcd->hc[pipe].toggle_in;
    }
    else
    {
        toggle = hhcd->hc[pipe].toggle_out;
    }
    return toggle;
}

/**
 * @brief
 *
 * @param Delay 延时的ms数.
 */
void USBH_Delay(uint32_t Delay)
{
    delay_ms(Delay);
}

/* USBD_LL_PCD callback function */

/**
 * @brief
 *
 * @param hhcd
 */
void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd)
{
    USBH_LL_IncTimer(hhcd->pData);
}

/**
 * @brief USBH 连接成功回调函数
 *
 * @param hhcd
 */
void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
{
    // usbx.bDeviceState|=1<<6;		//检测到USB插入
    // printf("Connected!\r\n\r\n");
    USBH_LL_Connect(hhcd->pData);
}

/**
 * @brief USBH 断开连接回调函数
 *
 * @param hhcd
 */
void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
{
    // usbx.bDeviceState=0;			//USB拔出
    // usbx.hdevclass=0;				//设备标记清零
    // printf("Disconnected!\r\n\r\n");
    USBH_LL_Disconnect(hhcd->pData);
}

/**
 * @brief USBH 通知URB变化回调函数
 *
 * @param hhcd
 * @param chnum 端点编号
 * @param urb_state URB状态
 */
void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
{
    // To be used with OS to sync URB state with the global state machine */
}


#endif // CONFIG_HAL_USB_HOST_MODULE_ENABLED
